home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / GDIMETA.PAK / METAFILE.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  16KB  |  551 lines

  1. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  2. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  3. // PARTICULAR PURPOSE.
  4. //
  5. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  6. //
  7. //  MODULE: metafile.c
  8. //
  9. //  PURPOSE: MetaFile manipulation functions.
  10. //
  11. //  FUNCTIONS:
  12. //    PictureWidth - Finds the width of an enhanced metafile (EMF)
  13. //    PictureHeight - Finds the height of an EMF
  14. //    LoadMetaFile - Loads any Windows type metafile (returns enhanced format)
  15. //    APMChecksum  - Calculate the checksum for a placeable metafile
  16. //    LoadPlaceableMetaFile - Converts a placeable metafile to enhanced format
  17. //    SavePlaceableMetaFile - Saves an enhanced metafile in placeable format
  18. //    CreateMetaPalette - Creates a GDI palette from an EMF color table
  19. //    GetDCFromEMF - Creates a new metafile DC and copies existing EMF to it
  20. //
  21. //  COMMENTS:
  22. //
  23.  
  24.  
  25. #include <windows.h>            // required for all Windows applications
  26. #include <windowsx.h>
  27. #include <commctrl.h>
  28. #include "globals.h"            // prototypes specific to this application
  29. #include <stdlib.h>             // for _splitpath
  30. #include "metafile.h"           // prototypes specific to this module
  31. #include "palette.h"            // for PALVERSION
  32.  
  33.  
  34. //
  35. //  FUNCTION: PictureWidth(HENHMETAFILE)
  36. //
  37. //  PURPOSE: Calculates the width in pixels of an enhanced metafile.
  38. //
  39. //  PARAMETERS:
  40. //    hemf - The metafile
  41. //
  42. //  RETURN VALUE:
  43. //    The width of the metafile, or 0 if not successful.
  44. //
  45. //  COMMENTS:
  46. //    The width of the metafiles rclFrame rect (.01mm units) is converted
  47. //    to pixels using the szlDevice and szlMillimeters members.
  48. //
  49.  
  50. UINT PictureWidth(HENHMETAFILE hemf)
  51. {
  52.     ENHMETAHEADER emh;
  53.  
  54.     if (!hemf)
  55.         return 0;
  56.  
  57.     if (GetEnhMetaFileHeader(hemf, sizeof(emh), &emh))
  58.         return MulDiv(RECTWIDTH(&emh.rclFrame),
  59.                       emh.szlDevice.cx,
  60.                       emh.szlMillimeters.cx * 100);
  61.     else
  62.         return 0;
  63. }
  64.  
  65.  
  66. //
  67. //  FUNCTION: PictureHeight(HENHMETAFILE)
  68. //
  69. //  PURPOSE: Calculates the height in pixels of an enhanced metafile.
  70. //
  71. //  PARAMETERS:
  72. //    hemf - The metafile
  73. //
  74. //  RETURN VALUE:
  75. //    The height of the metafile, or 0 if not successful.
  76. //
  77. //  COMMENTS:
  78. //    The height of the metafiles rclFrame rect (.01mm units) is converted
  79. //    to pixels using the szlDevice and szlMillimeters members.
  80. //
  81.  
  82. UINT PictureHeight(HENHMETAFILE hemf)
  83. {
  84.     ENHMETAHEADER emh;
  85.  
  86.     if (!hemf)
  87.         return 0;
  88.  
  89.     if (GetEnhMetaFileHeader(hemf, sizeof(emh), &emh))
  90.         return MulDiv(RECTHEIGHT(&emh.rclFrame),
  91.                       emh.szlDevice.cy,
  92.                       emh.szlMillimeters.cy * 100);
  93.     else
  94.         return 0;
  95. }
  96.  
  97. //
  98. //  FUNCTION: LoadMetaFile(LPCSTR)
  99. //
  100. //  PURPOSE: Loads an Enhanced, Placeable or standard Windows MetaFile
  101. //    from the given file, and converts it to enhanced format if necessary.
  102. //
  103. //  PARAMETERS:
  104. //    lpszFile  - The file to load
  105. //
  106. //  RETURN VALUE:
  107. //    The handle to an Enhanced MetaFile, or NULL if not successful.
  108. //
  109. //  COMMENTS:
  110. //
  111. //
  112.  
  113. HENHMETAFILE LoadMetaFile(LPCSTR lpszFile)
  114. {
  115.      HENHMETAFILE    hemf;
  116.     FILEMAP         fMap;
  117.  
  118.  
  119.     if (!MapFileReadOnly(lpszFile, NULL, &fMap))
  120.     {
  121.         OutputDebugString("LMF: MapFileReadOnly failed\r\n");
  122.         return NULL;
  123.     }
  124.  
  125.     //
  126.     // First check to see if it is an enhanced metafile
  127.     //
  128.     if (((LPENHMETAHEADER)fMap.pFileMap)->dSignature == ENHMETA_SIGNATURE)
  129.     {
  130.         OutputDebugString("LMF: Loading Enhanced metafile\r\n");
  131.  
  132.         hemf = GetEnhMetaFile(lpszFile);
  133.  
  134.         if (!hemf)
  135.             OutputDebugString("LMF: GetEnhMetaFile failed\r\n");
  136.     }
  137.  
  138.     //
  139.     // Not an enhanced metafile... check for Aldus Placeable Metafile (APM)
  140.     //
  141.     else if (*((LPDWORD)fMap.pFileMap) == APM_SIGNATURE)
  142.     {
  143.         OutputDebugString("LMF: Loading Placeable metafile\r\n");
  144.  
  145.         hemf = LoadPlaceableMetaFile((PAPMFILEHEADER)fMap.pFileMap);
  146.  
  147.         if (!hemf)
  148.             OutputDebugString("LMF: LoadPlaceableMetaFile failed\r\n");
  149.     }
  150.  
  151.     //
  152.     // Not enhanced or placeable... must be a Windows 3x metafile (we hope)
  153.     //
  154.     else
  155.     {
  156.         OutputDebugString("LMF: Loading Windows metafile\r\n");
  157.  
  158.         hemf = SetWinMetaFileBits(GetFileSize(fMap.hFile, NULL), //uiSize,
  159.                                   (PBYTE)fMap.pFileMap,
  160.                                   NULL,
  161.                                   NULL);
  162.  
  163.         if (!hemf)
  164.             OutputDebugString("LMF: SetWinMetaFileBits failed\r\n");
  165.     }
  166.  
  167.     CloseFileMapping(&fMap);
  168.     return hemf;
  169. }
  170.  
  171.  
  172. //
  173. //  FUNCTION: APMChecksum(PAPMFILEHEADER)
  174. //
  175. //  PURPOSE: Calculates the checksum for an Aldus Placeable Metafile (APM).
  176. //
  177. //  PARAMETERS:
  178. //    papm - the placeable header to calculate the checksum for.
  179. //
  180. //  RETURN VALUE:
  181. //    The checksum for the header.
  182. //
  183. //  COMMENTS:
  184. //    The checksum is calculated by XOR-ing together the first 10 WORD's
  185. //    of the header.
  186. //
  187. //
  188.  
  189. WORD APMChecksum(PAPMFILEHEADER papm)
  190. {
  191.     PWORD pw = (LPWORD)papm;
  192.     WORD  wSum = 0;
  193.     int   i;
  194.  
  195.     // The checksum in a Placeable Metafile header is calculated
  196.     // by XOR-ing the first 10 words of the header.
  197.  
  198.     for (i = 0; i < 10; i++)
  199.         wSum ^= *pw++;
  200.  
  201.     return wSum;
  202. }
  203.  
  204.  
  205. //
  206. //  FUNCTION: LoadPlaceableMetaFile(PAPMFILEHEADER)
  207. //
  208. //  PURPOSE: Converts a Placeable MetaFile into Enhanced MetaFile format.
  209. //
  210. //  PARAMETERS:
  211. //    papm - pointer to the placeable metafile to convert.
  212. //
  213. //  RETURN VALUE:
  214. //    The handle to an Enhanced MetaFile, or NULL if not successful.
  215. //
  216. //  COMMENTS:
  217. //
  218. //
  219.  
  220. HENHMETAFILE LoadPlaceableMetaFile(PAPMFILEHEADER papm)
  221. {
  222.     PMETAHEADER  pmf = (PMETAHEADER)(papm + 1);     // Windows MetaFile
  223.     METAFILEPICT mfp;
  224.     HENHMETAFILE hemf;
  225.     HDC          hdc;
  226.  
  227. #ifdef _DEBUG
  228.     if (APMChecksum(papm) != papm->checksum)
  229.         OutputDebugString("LPM: Placeable metafile checksum mismatch\r\n");
  230. #endif
  231.  
  232.     //
  233.     // Set up a METAFILEPICT with MM_ANISOTROPIC (requires xExt and
  234.     // yExt to be in MM_HIMETRIC units).
  235.     //
  236.     // Note: papm->bbox   = bounding rect in metafile units
  237.     //       papm->inch   = # of metafile units per inch
  238.     //       HIMETRICINCH = # of hi-metric units (.01mm) per inch
  239.     //
  240.     mfp.mm   = MM_ANISOTROPIC;
  241.     mfp.xExt = MulDiv(papm->bbox.right - papm->bbox.left,
  242.                       HIMETRICINCH,
  243.                       papm->inch);
  244.     mfp.yExt = MulDiv(papm->bbox.bottom - papm->bbox.top,
  245.                       HIMETRICINCH,
  246.                       papm->inch);
  247.     mfp.hMF  = NULL;
  248.  
  249.  
  250.     // Reference DC for SetWinMetaFileBits
  251.     hdc = GetDC(NULL);
  252.  
  253.     //
  254.     // Finally, convert it to an enhanced metafile.
  255.     //
  256.     hemf = SetWinMetaFileBits(pmf->mtSize * 2, (PBYTE)pmf, hdc, &mfp);
  257.  
  258.     ReleaseDC(NULL, hdc);
  259.     return hemf;
  260. }
  261.  
  262.  
  263. //
  264. //  FUNCTION: SavePlaceableMetaFile(HENHMETAFILE, LPCSTR)
  265. //
  266. //  PURPOSE: Saves an Enhanced MetaFile in Placeable MetaFile format.
  267. //
  268. //  PARAMETERS:
  269. //    hemf     - handle of the enhanced metafile to save.
  270. //    lpszFile - name of file to save to.
  271. //
  272. //  RETURN VALUE:
  273. //    TRUE if successful, FALSE otherwise.
  274. //
  275. //  COMMENTS:
  276. //    Uses memory mapped files to save the metafile.
  277. //
  278. //
  279.  
  280. BOOL SavePlaceableMetaFile(HENHMETAFILE hemf, LPCSTR lpszFile)
  281. {
  282.     FILEMAP         fMap;
  283.     ENHMETAHEADER   emh;
  284.     PAPMFILEHEADER  papm;
  285.     HDC             hdc;
  286.     UINT            uiSize;
  287.      BOOL            bRet;
  288.     int             nXdpi, nYdpi;
  289.  
  290.  
  291.     if (!lpszFile || !*lpszFile)
  292.     {
  293.         OutputDebugString("SPM: No Filename specified\r\n");
  294.         return FALSE;
  295.     }
  296.  
  297.     // Get information about the metafile
  298.     uiSize = GetEnhMetaFileHeader(hemf, sizeof(emh), &emh);
  299.     if (0 == uiSize)
  300.     {
  301.         OutputDebugString("SPM: GetEnhMetaFileHeader failed\r\n");
  302.         return FALSE;
  303.     }
  304.  
  305.     // Reference DC for GetWinMetaFileBits
  306.     hdc = GetDC(NULL);
  307.  
  308.     // Get the size of the metafile in Windows format
  309.     uiSize = GetWinMetaFileBits(hemf, 0, NULL, MM_ANISOTROPIC, hdc);
  310.     if (0 == uiSize)
  311.     {
  312.         OutputDebugString("SPM: GetWinMetaFileBits failed\r\n");
  313.  
  314.         ReleaseDC(NULL, hdc);
  315.         return FALSE;
  316.     }
  317.  
  318.     // Create a file mapping to write to
  319.     if (!MapFileReadWrite(lpszFile,
  320.                       NULL,
  321.                       &fMap,
  322.                       CREATE_ALWAYS,
  323.                       sizeof(APMFILEHEADER) + uiSize))
  324.     {
  325.         OutputDebugString("SPM: MapFileReadWrite failed\r\n");
  326.  
  327.         ReleaseDC(NULL, hdc);
  328.         return FALSE;
  329.     }
  330.  
  331.  
  332.     // Fill out the placeable metafile header
  333.  
  334.     nXdpi = GetDeviceCaps(hdc, LOGPIXELSX);
  335.     nYdpi = GetDeviceCaps(hdc, LOGPIXELSY);
  336.     papm  = (PAPMFILEHEADER)fMap.pFileMap;
  337.  
  338.     papm->key         = APM_SIGNATURE;
  339.     papm->hmf         = 0;
  340.     papm->inch        = 1000;   // somewhat arbitrary
  341.     papm->bbox.left   = (short) MulDiv(emh.rclBounds.left,   papm->inch, nXdpi);
  342.     papm->bbox.top    = (short) MulDiv(emh.rclBounds.top,    papm->inch, nYdpi);
  343.     papm->bbox.right  = (short) MulDiv(emh.rclBounds.right,  papm->inch, nXdpi);
  344.     papm->bbox.bottom = (short) MulDiv(emh.rclBounds.bottom, papm->inch, nYdpi);
  345.     papm->reserved    = 0;
  346.     papm->checksum    = APMChecksum(papm);
  347.  
  348.  
  349.     // Have the system convert the metafile to windows format and store
  350.     // it directly in the file.
  351.  
  352.     bRet = (uiSize == GetWinMetaFileBits(hemf,
  353.                                          uiSize,
  354.                                          (LPBYTE)(papm + 1),
  355.                                          MM_ANISOTROPIC,
  356.                                          hdc));
  357.  
  358.     ReleaseDC(NULL, hdc);       // clean up
  359.     CloseFileMapping(&fMap);
  360.     if (!bRet)
  361.     {
  362.         OutputDebugString("SPM: GetWinMetaFileBits failed\r\n");
  363.  
  364.         DeleteFile(lpszFile);
  365.     }
  366.  
  367.     return bRet;
  368. }
  369.  
  370. //
  371. //  FUNCTION: CreateMetaPalette(HENHMETAFILE)
  372. //
  373. //  PURPOSE: Creates a logical palette from an enhanced metafile's
  374. //    color table.
  375. //
  376. //  PARAMETERS:
  377. //    hemf - handle of the enhanced metafile
  378. //
  379. //  RETURN VALUE:
  380. //    The logical palette handle, or NULL if the metafile does not have
  381. //    a color table.
  382. //
  383. //  COMMENTS:
  384. //
  385. //
  386.  
  387. HPALETTE CreateMetaPalette(HENHMETAFILE hemf)
  388. {
  389.     HPALETTE hPal = NULL;
  390.     UINT nEntries;
  391.  
  392.     nEntries = GetEnhMetaFilePaletteEntries(hemf, 0, NULL);
  393.     if (nEntries != GDI_ERROR && nEntries != 0)
  394.     {
  395.         PLOGPALETTE plogPal;
  396.  
  397.         plogPal = (PLOGPALETTE)GlobalAllocPtr(GPTR,
  398.                         2 * sizeof(WORD) + sizeof(PALETTEENTRY) * nEntries);
  399.  
  400.         if (!plogPal)
  401.         {
  402.             OutputDebugString("CMP: Unable to allocate memory for LOGPALETTE\r\n");
  403.             return NULL;
  404.         }
  405.  
  406.         plogPal->palVersion = (WORD) PALVERSION;
  407.         plogPal->palNumEntries = (WORD) nEntries;
  408.         if (nEntries == GetEnhMetaFilePaletteEntries(hemf,
  409.                                                      nEntries,
  410.                                                      plogPal->palPalEntry))
  411.             hPal = CreatePalette(plogPal);
  412.  
  413.         else
  414.             OutputDebugString("CMP: GetEnhMetaFilePaletteEntries failed\r\n");
  415.  
  416.         (void) GlobalFreePtr(plogPal);
  417.     }
  418.  
  419.     return hPal;
  420. }
  421.  
  422.  
  423. //
  424. //  FUNCTION: GetDCFromEMF(HWND, HENHMETAFILE, HPALETTE)
  425. //
  426. //  PURPOSE: Creates a new enhanced metafile dc and optionally
  427. //    copies an existing metafile into the new dc.
  428. //
  429. //  PARAMETERS:
  430. //    hwnd - window used for reference
  431. //    hemf - existing metafile (or NULL)
  432. //    hpal - palette to use for new metafile (or NULL)
  433. //
  434. //  RETURN VALUE:
  435. //    The new metafile DC, or NULL if error
  436. //
  437. //  COMMENTS:
  438. //    Always uses the screen as the reference dc for the new
  439. //    metafile.
  440. //
  441. //
  442.  
  443. HDC GetDCFromEMF(HWND hwnd, HENHMETAFILE hemf, HPALETTE hpal)
  444. {
  445.     HDC     hdc;
  446.     RECT    rc = {0, 0, 500, 500};
  447.     TCHAR   szDesc[256];
  448.     TCHAR   szTitle[256] = "";
  449.     HCURSOR hcurSave = NULL;
  450.     ENHMETAHEADER emh;
  451.  
  452.  
  453.     // If we are copying an existing metafile, use its dimensions and title
  454.     // for the new metafile.
  455.     if (hemf)
  456.     {
  457.         // Copying the old metafile (later) can be slow, so put up hourglass
  458.         hcurSave = SetCursor(hcursHourGlass);
  459.  
  460.         if (GetEnhMetaFileHeader(hemf, sizeof(emh), &emh))
  461.         {
  462.             // Get the rclFrame rect from the header (HiMetric units)
  463.             CopyRect(&rc, (LPRECT)&emh.rclFrame);
  464.  
  465.             // Get the title from the metafile's description string
  466.             GetEnhMetaFileDescription(hemf, sizeof(szDesc), szDesc);
  467.             lstrcpy(szTitle, szDesc + lstrlen(szDesc) + 1);
  468.         }
  469.         else    // Must be an invalid metafile (or something drastic)
  470.         {
  471.             OutputDebugString("GetDCFromEMF: GetEnhMetaFileHeader failed!\r\n");
  472.             SetCursor(hcurSave);
  473.             return NULL;
  474.         }
  475.     }
  476.  
  477.     // If there's no existing metafile, try the window dimensions.
  478.     else
  479.     {
  480.         if (hwnd)
  481.         {
  482.             GetClientRect(hwnd, &rc);
  483.             rc.right--;       // EMF interprets right/bottom as being included
  484.             rc.bottom--;
  485.         }
  486.         // else use defaults
  487.  
  488.         // Convert pixels to MM_HIMETRIC units for CreateEnhMetaFile
  489.  
  490.         hdc = GetDC(hwnd); // NULL hwnd is OK here
  491.         rc.right  = MulDiv(rc.right,
  492.                            HIMETRICINCH,
  493.                            GetDeviceCaps(hdc, LOGPIXELSX));
  494.         rc.bottom = MulDiv(rc.bottom,
  495.                            HIMETRICINCH,
  496.                            GetDeviceCaps(hdc, LOGPIXELSY));
  497.         ReleaseDC(hwnd, hdc);
  498.     }
  499.  
  500.     // If we don't have a title yet, use the filename. If we don't have a
  501.     // filename, go with an empty title for now.
  502.     if (szTitle[0] == 0 && GetFName()[0] != 0)
  503.         _splitpath(GetFName(), NULL, NULL, szTitle, NULL);
  504.  
  505.     // New description = our app name + title
  506.     wsprintf(szDesc, "%s\0%s\0\0", szAppName, szTitle);
  507.  
  508.  
  509.     // Create the metafile DC (use screen for reference)
  510.     hdc = CreateEnhMetaFile(NULL, NULL, &rc, szDesc);
  511.  
  512.     if (hdc)
  513.     {
  514.         // Use text mode to avoid rounding errors
  515.         SetMapMode(hdc, MM_TEXT);
  516.  
  517.         // Set the metafile's color table
  518.         if (hpal)
  519.         {
  520.             SelectPalette(hdc, hpal, FALSE);
  521.             RealizePalette(hdc);
  522.         }
  523.  
  524.         // Copy old metafile into new one
  525.         if (hemf)
  526.         {
  527.             // Convert rect to logical units (pixels here) for PlayEnhMetaFile
  528.             rc.left   = MulDiv(rc.left,
  529.                                emh.szlDevice.cx,
  530.                                emh.szlMillimeters.cx * 100);
  531.             rc.top    = MulDiv(rc.top,
  532.                                emh.szlDevice.cy,
  533.                                emh.szlMillimeters.cy * 100);
  534.             rc.right  = MulDiv(rc.right,
  535.                                emh.szlDevice.cx,
  536.                                emh.szlMillimeters.cx * 100);
  537.             rc.bottom = MulDiv(rc.bottom,
  538.                                emh.szlDevice.cy,
  539.                                emh.szlMillimeters.cy * 100);
  540.  
  541.             PlayEnhMetaFile(hdc, hemf, &rc);
  542.         }
  543.     }
  544.  
  545.     // Restore original cursor
  546.     if (hcurSave)
  547.         SetCursor(hcurSave);
  548.  
  549.     return hdc;
  550. }
  551.